#ifndef GRAPHPREDICATES_HPP_INCLUDED
#define GRAPHPREDICATES_HPP_INCLUDED

#include "GraphDatabase.hpp"


#include <boost/graph/graph_traits.hpp>
#include "boost/tuple/tuple.hpp"
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/subgraph.hpp>
#include "boost/tuple/tuple_io.hpp"
#include <string>
#include <vector>
#include "Graph.hpp"
#include <iomanip>

namespace TopologicalLearner
{

struct HexCharStruct
{
  unsigned char c;
  HexCharStruct(char _c) : c(_c) { }
};

inline std::ostream& operator<<(std::ostream& o, const HexCharStruct& hs)
{
  return (o << std::setw(2) << std::setfill('0') << std::hex << (int)hs.c);
}

inline HexCharStruct hex(char _c)
{
  return HexCharStruct(_c);
}


/**
 * An object that handles the writing of the properties of each vertex when exporting a graph to the dot format
 */
class Vertex_writer
{

private:
    Graph graph;
    const std::vector<const Graph*> m_pOverlaygraph;
    const GraphDatabase* m_pD;

public:

    Vertex_writer(Graph _graph, const GraphDatabase* pD) : graph(_graph), m_pD(pD)  {}
    Vertex_writer(Graph _graph, const GraphDatabase* pD, std::vector<const Graph*> _pOverlay) : graph(_graph), m_pOverlaygraph(_pOverlay), m_pD(pD)  {}

    void operator()(std::ostream& out, const Vertex& v) const;

};


/**
 * An object that handles the writing of the properties of each edge when exporting a graph to the dot format
 */
template <typename GeneralGraph>
class Edge_writer
{
public:
    Edge_writer(GeneralGraph _graph, std::vector<const GeneralGraph*> _pOverlay) : graph(_graph), m_pOverlaygraph(_pOverlay) {}


    template <typename Edge>
    void operator()(std::ostream& out, const Edge& e) const
    {
        unsigned char R = 0, G = 0, B = 0, A = 255;
        typename boost::graph_traits<GeneralGraph>::edge_iterator firstE, lastE;
        unsigned int iS = boost::get(boost::vertex_name, graph, source(e, graph));
        unsigned int iT = boost::get(boost::vertex_name, graph, target(e, graph));
        bool bMatch0 = false;
        bool bMatch1 = false;
        bool bMatch2 = false;




        /*
    // Yellow means it is predicted and in the partial
    // Red means its only in the partial and not in the predicted

          */

        for(unsigned int j=0; j < m_pOverlaygraph.size(); j++)
        {
            for (boost::tie(firstE, lastE) = boost::edges(*m_pOverlaygraph[j]); firstE != lastE; ++firstE)
            {
                if( (boost::get(boost::vertex_name, *m_pOverlaygraph[j], source(*firstE, *m_pOverlaygraph[j])) == iS &&
                     boost::get(boost::vertex_name, *m_pOverlaygraph[j], target(*firstE, *m_pOverlaygraph[j])) == iT) ||
                        (boost::get(boost::vertex_name, *m_pOverlaygraph[j], source(*firstE, *m_pOverlaygraph[j])) == iT &&
                         boost::get(boost::vertex_name, *m_pOverlaygraph[j], target(*firstE, *m_pOverlaygraph[j])) == iS)  )
                {
                    if( j == 0 ) { R = 255; bMatch0 = true; }
                    else if( j == 1 ) {  G = 0; B = 0;  bMatch1 = true;  }
                    else if ( j==2 ) {bMatch2 = true;  }
                }

            }
        }


        if(m_pOverlaygraph.size() == 3)
        {
        // Green means its predicted and in the actual graph but not observed yet
        if(bMatch1 && bMatch2 && !bMatch0)
        { R = 0; G = 255; B = 0; }

        // Red means its predicted but not in the actual graph
        if(bMatch1 && !bMatch2 && !bMatch0)
        { R = 255; G = 0; B = 0; }

        // Yellow means its in the partial graph but not in the hypothesis
        if(bMatch0 && !bMatch1)
        { R = 255; G = 255; B = 0; }

        // Blue means its in the hypothesis, observed
        if(bMatch0 && bMatch2 && bMatch1)
        { R = 0; G = 0; B = 255; }

        // Black is normal color
        if(!bMatch0 && !bMatch1 && !bMatch2)
        { R = 0; G = 0; B = 0; }
        }

        out << "[color=\"#" << hex(R) << hex(G) << hex(B) << hex(A) << "\"]";
    }


private:
    GeneralGraph graph;
    const std::vector<const GeneralGraph*> m_pOverlaygraph;
};


}



#endif // GRAPHPREDICATES_HPP_INCLUDED

